from typing import Optional

from kubernetes_asyncio import client

from balder.services.kube_base import KubeBase, format_containers_and_volumes, format_selector


class DeploymentService(KubeBase):
    async def create_deployment(
            self,
            namespace: str,
            name: str,
            containers: list[dict],
            volumes: list[dict] = None,
            replicas: int = 1,
            restart_policy: str = "Always",
            node_selector: dict = None,
            init_containers: Optional[list[dict]] = None
    ) -> client.V1Deployment:
        """
        创建deployment
        :param namespace: namespace
        :param name: deployment name
        :param containers: containers的配置
            一个例子如下：

            containers = [
                {
                    "name": "nginx",
                    "image": "nginx:1.14.2",
                    "image_pull_policy": "IfNotPresent",
                    "command": ["nginx"],
                    "args": ["-g", "daemon off;"],
                    "ports": [
                        {
                            "name": "http",
                            "container_port": 80,
                            "protocol": "TCP"
                        }
                    ],
                    "env": [{
                        "name": "test",
                        "value": "test"
                    }],
                    "volume_mounts": [
                        {
                            "name": "test-volume",
                            "mount_path": "/tmp",
                            "read_only": False,
                            "sub_path": "test",
                            "mount_propagation": "None",
                            "sub_path_expr": "test"
                        }
                    ],
                    "resources": {
                        "requests": {
                            "cpu": "100m",
                            "memory": "128Mi"
                        },
                        "limits": {
                            "cpu": "200m",
                            "memory": "256Mi"
                        }
                    },
                    gpu: [
                        {
                            "type": "bi-v100",
                            "core": 100,
                            "memory": 128
                        }
                    ]
                }
            ]
        :param volumes: volumes的配置
            一个例子如下：

            volumes = [
                {
                    "name": "test-volume",
                    "persistent_volume_claim": {
                        "claim_name": "test-pvc"
                    }
                }
            ]
        :param replicas: 副本数
        :param restart_policy: 重启策略
        :param node_selector: node_selector，字典形式，如{'kubernetes.io/hostname': 'node1'}
        :param init_containers: initContainers的配置
        """
        containers, volumes, init_containers = format_containers_and_volumes(containers, volumes, init_containers)

        deployment = client.V1Deployment(
            api_version='apps/v1',
            kind='Deployment',
            metadata=client.V1ObjectMeta(name=name),
            spec=client.V1DeploymentSpec(
                replicas=replicas,
                selector=client.V1LabelSelector(
                    match_labels={'app': name}
                ),
                template=client.V1PodTemplateSpec(
                    metadata=client.V1ObjectMeta(labels={'app': name}),
                    spec=client.V1PodSpec(
                        containers=containers,
                        volumes=volumes,
                        node_selector=node_selector,
                        init_containers=init_containers,
                        restart_policy=restart_policy
                    )
                )
            )
        )

        return await self.app_v1_api.create_namespaced_deployment(namespace=namespace, body=deployment)

    async def list_namespaced_deployment(self, namespace: str, label_selector: Optional[dict] = None, field_selector: Optional[dict] = None) -> client.V1DeploymentList:
        deployment_label_selector, deployment_field_selector = format_selector(label_selector, field_selector)
        return await self.app_v1_api.list_namespaced_deployment(
            namespace=namespace,
            label_selector=deployment_label_selector,
            field_selector=deployment_field_selector
        )

    async def delete_namespaced_deployment(self, namespace: str, name: str) -> client.V1Status:
        return await self.app_v1_api.delete_namespaced_deployment(name=name, namespace=namespace)
